home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / What's New? / Development Kits / Apple Game Sprockets DR1 / Examples / DroneZone / DZDrone.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-24  |  45.0 KB  |  1,641 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    File:        DZDrone.c
  3.  *    Author:        Dan Venolia
  4.  *
  5.  *    Contents:    A drone object represents the position of an player or drone.
  6.  *
  7.  *    Copyright © 1996 Apple Computer, Inc.
  8.  */
  9.  
  10. #include <assert.h>
  11. #include <math.h>
  12. #include <stdlib.h>
  13.  
  14. #include <Events.h>
  15. #include <QuickDraw.h>
  16. #include <Resources.h>
  17. #include <Sound.h>
  18. #include <SoundInput.h>
  19. #include <Types.h>
  20.  
  21. #include <QD3D.h>
  22. #include <QD3DCamera.h>
  23. #include <QD3DDrawContext.h>
  24. #include <QD3DGeometry.h>
  25. #include <QD3DMath.h>
  26. #include <QD3DPick.h>
  27. #include <QD3DSet.h>
  28. #include <QD3DShader.h>
  29. #include <QD3DStyle.h>
  30. #include <QD3DTransform.h>
  31. #include <QD3DView.h>
  32.  
  33. #include "SoundSprocket.h"
  34.  
  35. #include "DZDisplay.h"
  36. #include "DZDrone.h"
  37. #include "DZGame.h"
  38. #include "DZResource.h"
  39. #include "DZSound.h"
  40. #include "DZThumbprint.h"
  41. #include "DZUtils.h"
  42.  
  43. #define IS_SELF_DRONE(inDrone)        (inDrone->thumbprint == kThumbprint_SelfDrone)
  44. #define IS_AUTO_DRONE(inDrone)        (inDrone->thumbprint == kThumbprint_AutoDrone)
  45. #define IS_BULLET_DRONE(inDrone)    (inDrone->thumbprint == kThumbprint_BulletDrone)
  46. #define IS_DRONE(inDrone)            (IS_SELF_DRONE(inDrone) || IS_AUTO_DRONE(inDrone) || IS_BULLET_DRONE(inDrone))
  47.  
  48. #define SELF_DRONE_SPEED            1.0        // In units per second
  49.  
  50. #define AUTO_DRONE_LEAD                5.0        // Drone target leads by this distance (in units)
  51. #define AUTO_DRONE_ACCEL            2.0        // Drone acceleration (units per second per second)
  52. #define AUTO_DRONE_TURN_RATE        1.8        // In radians per second
  53. #define AUTO_DRONE_BURN_TIME        3.0        // In seconds
  54. #define AUTO_DRONE_REST_TIME        1.0        // In seconds
  55. #define AUTO_DRONE_EXPLOSION_TIME    3.0        // In seconds
  56. #define AUTO_DRONE_FADE_TIME        0.25    // Fraction of AUTO_DRONE_EXPLOSION_TIME for fade
  57. #define AUTO_DRONE_MIN_SCALE        0.2        // Initial scale for explosion
  58.  
  59. #define AUTO_DRONE_IDLE_REF_DIST    2.0
  60. #define AUTO_DRONE_BURN_REF_DIST    5.0
  61. #define AUTO_DRONE_EXPL_REF_DIST    30.0
  62.  
  63. #define BULLET_DRONE_OFFSET            0.2        // Offset from self to bullet initial position
  64. #define BULLET_DRONE_SPEED            50.0    // In units per second
  65. #define BULLET_DRONE_LIMIT            50.0    // Maximum length of a bullet
  66.  
  67. #define HUD_SCALE                    0.02    // Scale of HUD
  68. #define HUD_HEIGHT                    0.5        // cos(angle) at which to consider out-of-plane
  69.  
  70.  
  71. enum {
  72.     kDroneDrawContextSize            = 5        // Used for picking
  73. };
  74.  
  75.  
  76. typedef enum TDroneOrder {                    // In order of evaluation
  77.     kDroneOrder_Self,
  78.     kDroneOrder_Auto,
  79.     kDroneOrder_Bullet
  80. } TDroneOrder;
  81.  
  82.  
  83. typedef void (*TDroneMoveMethod)(
  84.     TDroneObject            inDrone);
  85.  
  86. typedef void (*TDroneUpdateSoundMethod)(
  87.     TDroneObject            inDrone);
  88.  
  89. typedef void (*TDroneSubmitMethod)(
  90.     TDroneObject            inDrone,
  91.     Boolean                    inHUDVisible,
  92.     TQ3ViewObject            inView);
  93.  
  94. typedef void (*TDronePickSubmitMethod)(
  95.     TDroneObject            inDrone,
  96.     TQ3ViewObject            inView);
  97.  
  98. typedef void (*TDroneHitMethod)(
  99.     TDroneObject            inDrone);
  100.  
  101.  
  102. typedef enum TAutoSound {
  103.     kAutoSound_None,
  104.     kAutoSound_Idle,
  105.     kAutoSound_Burn,
  106.     kAutoSound_Explosion
  107. } TAutoSound;
  108.  
  109. typedef enum TAutoMode {
  110.     kAutoMode_Idle,
  111.     kAutoMode_Burn,
  112.     kAutoMode_Rest,
  113.     kAutoMode_Explosion
  114. } TAutoMode;
  115.  
  116.  
  117. typedef struct TDroneData {
  118.     TThumbprint                thumbprint;            // For validation
  119.     
  120.     TDroneMoveMethod        moveMethod;            // Method: Drone_Move
  121.     TDroneUpdateSoundMethod    updateSoundMethod;    // Method: Drone_UpdateSound
  122.     TDroneSubmitMethod        submitMethod;        // Method: Drone_Submit
  123.     TDronePickSubmitMethod    pickSubmitMethod;    // Method: Drone_PickSubmit
  124.     TDroneHitMethod            hitMethod;            // Method: Drone_Hit
  125.     
  126.     TDroneObject            prev;                // The global list of drones
  127.     TDroneObject            next;
  128.     TDroneOrder                order;                // Sort key
  129.     
  130.     Boolean                    mark;                // Is this drone marked to die?
  131.     
  132.     TQ3Point3D                position;            // Current position
  133.     TQ3Point3D                position1;            // Previous position
  134.     
  135.     TQ3Vector3D                velocity;            // Change in position over time
  136.     TQ3Vector3D                velocity1;            // Previous velocity
  137.     
  138.     TQ3Vector3D                acceleration;        // Change in velocity over time
  139.     
  140.     TQ3Vector3D                direction;            // Forward        (model X axis)
  141.     TQ3Vector3D                up;                    // Vertical        (model Y axis)
  142.     TQ3Vector3D                cross;                // Horizontal    (model Z axis)
  143.     
  144.     TQ3Object                geometry;            // The shape of the drone
  145.     
  146.     SndChannelPtr            autoSndChannel;        // Auto: Sound channel
  147.     SourceReference            autoSource;            // Auto: 3D sound source
  148.     TAutoSound                autoSound;            // Auto: Sound currently playing
  149.     TDroneObject            autoInterest;        // Auto: Drone that we're looking at
  150.     TQ3Vector3D                autoVelocity;        // Auto: Drone velocity (instantaneous)
  151.     TAutoMode                autoMode;            // Auto: Current state
  152.     unsigned long            autoModeTimeout;    // Auto: When does mode expire?
  153.     float                    autoDistance;        // Auto: Last distance from target
  154.     float                    autoExplosion;        // Auto: 0=start; 1=end of explosion
  155.     
  156.     TQ3Point3D                bulletOrigin;        // Bullet: Starting position of the bullet
  157. } TDroneData;
  158.  
  159.  
  160. static TDroneObject            gDroneList                        = NULL;
  161. static TQ3Object            gDroneAutoGeometry                = NULL;
  162. static TQ3Object            gDroneAutoBurnGeometry            = NULL;
  163. static TQ3Object            gDroneAutoExplosionGeometry        = NULL;
  164. static TQ3AttributeSet        gDroneBulletColor                = NULL;
  165. static TQ3ShaderObject        gDroneNULLIllumination            = NULL;
  166. static TQ3ViewObject        gDroneView                        = NULL;
  167. static TQ3DrawContextObject    gDroneDrawContext                = NULL;
  168. static TQ3CameraObject        gDroneCamera                    = NULL;
  169. static TQ3PickObject        gDronePick                        = NULL;
  170.  
  171. static SndListHandle        gDroneAutoSndIdle                = NULL;
  172. static SndListHandle        gDroneAutoSndBurn                = NULL;
  173. static SndListHandle        gDroneAutoSndExplosion            = NULL;
  174.  
  175. static long                    gDroneAutoSndIdleOffset            = 0;
  176. static long                    gDroneAutoSndBurnOffset            = 0;
  177. static long                    gDroneAutoSndExplosionOffset    = 0;
  178.  
  179. static TQ3GeometryObject    gDroneAutoMarkerEqual            = NULL;
  180. static TQ3GeometryObject    gDroneAutoMarkerAbove            = NULL;
  181. static TQ3GeometryObject    gDroneAutoMarkerBelow            = NULL;
  182.  
  183. static unsigned char        gDroneAutoMarkerDataEqual[8] =
  184.                                     {0x38, 0x44, 0x82, 0x92, 0x82, 0x44, 0x38, 0x00};
  185.  
  186. static unsigned char        gDroneAutoMarkerDataAbove[8] =
  187.                                     {0x38, 0x54, 0x92, 0xFE, 0x92, 0x54, 0x38, 0x00};
  188.  
  189. static unsigned char        gDroneAutoMarkerDataBelow[8] =
  190.                                     {0x38, 0x44, 0x82, 0xFE, 0x82, 0x44, 0x38, 0x00};
  191.  
  192.  
  193. static TDroneObject Drone_New(
  194.     TDroneOrder                inOrder);
  195.  
  196. static void SelfDrone_Move(
  197.     TDroneObject            inDrone);
  198.  
  199. static void AutoDrone_Move(
  200.     TDroneObject            inDrone);
  201.  
  202. static void BulletDrone_Move(
  203.     TDroneObject            inDrone);
  204.  
  205. static void AutoDrone_UpdateSound(
  206.     TDroneObject            inDrone);
  207.  
  208. static void AutoDrone_Submit(
  209.     TDroneObject            inDrone,
  210.     Boolean                    inHUDVisible,
  211.     TQ3ViewObject            inView);
  212.  
  213. static void BulletDrone_Submit(
  214.     TDroneObject            inDrone,
  215.     Boolean                    inHUDVisible,
  216.     TQ3ViewObject            inView);
  217.  
  218. static void Drone_PickSubmit(
  219.     TDroneObject            inDrone,
  220.     TQ3ViewObject            inView);
  221.  
  222. static void AutoDrone_PickSubmit(
  223.     TDroneObject            inDrone,
  224.     TQ3ViewObject            inView);
  225.  
  226. static void Drone_Hit(
  227.     TDroneObject            inDrone);
  228.  
  229. static void AutoDrone_Hit(
  230.     TDroneObject            inDrone);
  231.  
  232. void Drone_GetMatrix(
  233.     TDroneObject            inDrone,
  234.     TQ3Matrix4x4*            outMatrix);
  235.  
  236.  
  237. /* =============================================================================
  238.  *        Drone_Init (external)
  239.  *
  240.  *    Initializes the drone stuff.
  241.  * ========================================================================== */
  242. void Drone_Init(
  243.     void)
  244. {
  245.     TQ3ColorRGB                        color;
  246.     TQ3PixmapDrawContextData        pixmapDrawContextData;
  247.     TQ3ViewAngleAspectCameraData    viewAngleCameraData;
  248.     TQ3WindowPointPickData            windowPointPickData;
  249.     TQ3MarkerData                    markerData;
  250.     
  251.     // Set up the autopilot drone geometry
  252.     gDroneAutoGeometry = Get3DMFResource(k3DMFID_AutoDrone);
  253.     assert(gDroneAutoGeometry != NULL);
  254.     
  255.     // Set up the autopilot drone burn geometry
  256.     gDroneAutoBurnGeometry = Get3DMFResource(k3DMFID_AutoDroneBurn);
  257.     assert(gDroneAutoBurnGeometry != NULL);
  258.     
  259.     // Set up the autopilot drone explosion geometry
  260.     gDroneAutoExplosionGeometry = Get3DMFResource(k3DMFID_AutoDroneExplosion);
  261.     assert(gDroneAutoExplosionGeometry != NULL);
  262.     
  263.     // Read in the autopilot drone sounds
  264.     gDroneAutoSndIdle = (SndListHandle) GetResource('snd ', kSndID_AutoIdle);
  265.     assert(gDroneAutoSndIdle != NULL);
  266.     
  267.     gDroneAutoSndBurn = (SndListHandle) GetResource('snd ', kSndID_AutoBurn);
  268.     assert(gDroneAutoSndBurn != NULL);
  269.     
  270.     gDroneAutoSndExplosion = (SndListHandle) GetResource('snd ', kSndID_AutoExplosion);
  271.     assert(gDroneAutoSndExplosion != NULL);
  272.     
  273.     GetSoundHeaderOffset(gDroneAutoSndIdle,            &gDroneAutoSndIdleOffset);
  274.     GetSoundHeaderOffset(gDroneAutoSndBurn,            &gDroneAutoSndBurnOffset);
  275.     GetSoundHeaderOffset(gDroneAutoSndExplosion,    &gDroneAutoSndExplosionOffset);
  276.     
  277.     // Set up the bullet drone line color
  278.     gDroneBulletColor = Q3AttributeSet_New();
  279.     assert(gDroneBulletColor != NULL);
  280.     
  281.     color.r = 1.0;
  282.     color.g = 0.8;
  283.     color.b = 0.1;
  284.     
  285.     Q3AttributeSet_Add(gDroneBulletColor, kQ3AttributeTypeDiffuseColor, &color);
  286.     
  287.     // Create the bullet null illum shader
  288.     gDroneNULLIllumination = Q3NULLIllumination_New();
  289.     assert(gDroneNULLIllumination != NULL);
  290.     
  291.     // Create the view that we use for bullet collision detection
  292.     gDroneView = Q3View_New();
  293.     assert(gDroneView != NULL);
  294.     
  295.     // Create its draw context
  296.     pixmapDrawContextData.drawContextData.clearImageMethod        = kQ3ClearMethodWithColor;
  297.     pixmapDrawContextData.drawContextData.clearImageColor.a        = 1.0;
  298.     pixmapDrawContextData.drawContextData.clearImageColor.r        = 0.0;
  299.     pixmapDrawContextData.drawContextData.clearImageColor.g        = 0.0;
  300.     pixmapDrawContextData.drawContextData.clearImageColor.b        = 0.0;
  301.     pixmapDrawContextData.drawContextData.paneState                = kQ3False;
  302.     pixmapDrawContextData.drawContextData.maskState                = kQ3False;
  303.     pixmapDrawContextData.drawContextData.doubleBufferState        = kQ3False;
  304.     pixmapDrawContextData.pixmap.width                            = kDroneDrawContextSize;
  305.     pixmapDrawContextData.pixmap.height                            = kDroneDrawContextSize;
  306.     pixmapDrawContextData.pixmap.rowBytes                        = pixmapDrawContextData.pixmap.width*4;
  307.     pixmapDrawContextData.pixmap.pixelSize                        = 32;
  308.     pixmapDrawContextData.pixmap.pixelType                        = kQ3PixelTypeRGB32;
  309.     pixmapDrawContextData.pixmap.bitOrder                        = kQ3EndianBig;
  310.     pixmapDrawContextData.pixmap.byteOrder                        = kQ3EndianBig;
  311.     pixmapDrawContextData.pixmap.image                            = malloc(pixmapDrawContextData.pixmap.height*pixmapDrawContextData.pixmap.rowBytes);
  312.     
  313.     gDroneDrawContext = Q3PixmapDrawContext_New(&pixmapDrawContextData);
  314.     assert(gDroneDrawContext != NULL);
  315.     
  316.     Q3View_SetDrawContext(gDroneView, gDroneDrawContext);
  317.     
  318.     // Create its camera
  319.     viewAngleCameraData.cameraData.placement.cameraLocation.x    = 0.0;
  320.     viewAngleCameraData.cameraData.placement.cameraLocation.y    = 0.0;
  321.     viewAngleCameraData.cameraData.placement.cameraLocation.z    = 0.0;
  322.     viewAngleCameraData.cameraData.placement.pointOfInterest.x    = 1.0;
  323.     viewAngleCameraData.cameraData.placement.pointOfInterest.y    = 0.0;
  324.     viewAngleCameraData.cameraData.placement.pointOfInterest.z    = 0.0;
  325.     viewAngleCameraData.cameraData.placement.upVector.x            = 0.0;
  326.     viewAngleCameraData.cameraData.placement.upVector.y            = 1.0;
  327.     viewAngleCameraData.cameraData.placement.upVector.z            = 0.0;
  328.     viewAngleCameraData.cameraData.range.hither                    = 0.1;
  329.     viewAngleCameraData.cameraData.range.yon                    = BULLET_DRONE_LIMIT;
  330.     viewAngleCameraData.cameraData.viewPort.origin.x            = -1.0;
  331.     viewAngleCameraData.cameraData.viewPort.origin.y            = 1.0;
  332.     viewAngleCameraData.cameraData.viewPort.width                = 2.0;
  333.     viewAngleCameraData.cameraData.viewPort.height                = 2.0;
  334.     viewAngleCameraData.fov                                        = 0.1;
  335.     viewAngleCameraData.aspectRatioXToY                            = pixmapDrawContextData.pixmap.width/pixmapDrawContextData.pixmap.height;
  336.  
  337.     gDroneCamera = Q3ViewAngleAspectCamera_New(&viewAngleCameraData);
  338.     assert(gDroneCamera != NULL);
  339.     
  340.     Q3View_SetCamera(gDroneView, gDroneCamera);
  341.     
  342.     // Create the pick object
  343.     windowPointPickData.data.sort                = kQ3PickSortNearToFar;
  344.     windowPointPickData.data.mask                = kQ3PickDetailMaskPickID | kQ3PickDetailMaskDistance;
  345.     windowPointPickData.data.numHitsToReturn    = kQ3ReturnAllHits;
  346.     windowPointPickData.point.x                    = 0.5*pixmapDrawContextData.pixmap.width;
  347.     windowPointPickData.point.y                    = 0.5*pixmapDrawContextData.pixmap.height;
  348.     windowPointPickData.vertexTolerance            = 0.0;
  349.     windowPointPickData.edgeTolerance            = 0.0;
  350.     
  351.     gDronePick = Q3WindowPointPick_New(&windowPointPickData);
  352.     assert(gDronePick != NULL);
  353.     
  354.     // Create the autodrone markers
  355.     markerData.location.x            = 0.0;
  356.     markerData.location.y            = 0.0;
  357.     markerData.location.z            = 0.0;
  358.     markerData.xOffset                = -3;
  359.     markerData.yOffset                = -3;
  360.     markerData.bitmap.width            = 8;
  361.     markerData.bitmap.height        = 8;
  362.     markerData.bitmap.rowBytes        = 1;
  363.     markerData.bitmap.bitOrder        = kQ3EndianBig;
  364.     markerData.markerAttributeSet    = Q3AttributeSet_New();
  365.     
  366.     assert(markerData.markerAttributeSet != NULL);
  367.     
  368.     color.r = 1.0;
  369.     color.g = 1.0;
  370.     color.b = 0.4;
  371.     
  372.     Q3AttributeSet_Add(markerData.markerAttributeSet, kQ3AttributeTypeDiffuseColor, &color);
  373.     
  374.     markerData.bitmap.image = (unsigned char*) gDroneAutoMarkerDataEqual;
  375.     gDroneAutoMarkerEqual = Q3Marker_New(&markerData);
  376.     assert(gDroneAutoMarkerEqual != NULL);
  377.     
  378.     markerData.bitmap.image = (unsigned char*) gDroneAutoMarkerDataAbove;
  379.     gDroneAutoMarkerAbove = Q3Marker_New(&markerData);
  380.     assert(gDroneAutoMarkerAbove != NULL);
  381.     
  382.     markerData.bitmap.image = (unsigned char*) gDroneAutoMarkerDataBelow;
  383.     gDroneAutoMarkerBelow = Q3Marker_New(&markerData);
  384.     assert(gDroneAutoMarkerBelow != NULL);
  385.     
  386.     Q3Object_Dispose(markerData.markerAttributeSet);
  387.     markerData.markerAttributeSet = NULL;
  388. }
  389.  
  390.  
  391. /* =============================================================================
  392.  *        Drone_Exit (external)
  393.  *
  394.  *    Prepares for exit.
  395.  * ========================================================================== */
  396. void Drone_Exit(
  397.     void)
  398. {
  399.     while (gDroneList != NULL)
  400.     {
  401.         Drone_Dispose(gDroneList);
  402.     }
  403.     
  404.     if (gDroneAutoGeometry != NULL)
  405.     {
  406.         Q3Object_Dispose(gDroneAutoGeometry);
  407.         gDroneAutoGeometry = NULL;
  408.     }
  409.     
  410.     if (gDroneAutoBurnGeometry != NULL)
  411.     {
  412.         Q3Object_Dispose(gDroneAutoBurnGeometry);
  413.         gDroneAutoBurnGeometry = NULL;
  414.     }
  415.     
  416.     if (gDroneAutoExplosionGeometry != NULL)
  417.     {
  418.         Q3Object_Dispose(gDroneAutoExplosionGeometry);
  419.         gDroneAutoExplosionGeometry = NULL;
  420.     }
  421.     
  422.     if (gDroneAutoSndIdle != NULL)
  423.     {
  424.         ReleaseResource((Handle) gDroneAutoSndIdle);
  425.         gDroneAutoSndIdle = NULL;
  426.     }
  427.     
  428.     if (gDroneAutoSndBurn != NULL)
  429.     {
  430.         ReleaseResource((Handle) gDroneAutoSndBurn);
  431.         gDroneAutoSndBurn = NULL;
  432.     }
  433.     
  434.     if (gDroneAutoSndExplosion != NULL)
  435.     {
  436.         ReleaseResource((Handle) gDroneAutoSndExplosion);
  437.         gDroneAutoSndExplosion = NULL;
  438.     }
  439.     
  440.     if (gDroneBulletColor != NULL)
  441.     {
  442.         Q3Object_Dispose(gDroneBulletColor);
  443.         gDroneBulletColor = NULL;
  444.     }
  445.     
  446.     if (gDroneNULLIllumination != NULL)
  447.     {
  448.         Q3Object_Dispose(gDroneNULLIllumination);
  449.         gDroneNULLIllumination = NULL;
  450.     }
  451.     
  452.     if (gDroneView != NULL)
  453.     {
  454.         Q3Object_Dispose(gDroneView);
  455.         gDroneView = NULL;
  456.     }
  457.     
  458.     if (gDroneDrawContext != NULL)
  459.     {
  460.         Q3Object_Dispose(gDroneDrawContext);
  461.         gDroneDrawContext = NULL;
  462.     }
  463.     
  464.     if (gDroneCamera != NULL)
  465.     {
  466.         Q3Object_Dispose(gDroneCamera);
  467.         gDroneCamera = NULL;
  468.     }
  469.     
  470.     if (gDronePick != NULL)
  471.     {
  472.         Q3Object_Dispose(gDronePick);
  473.         gDronePick = NULL;
  474.     }
  475.     
  476.     if (gDroneAutoMarkerEqual != NULL)
  477.     {
  478.         Q3Object_Dispose(gDroneAutoMarkerEqual);
  479.         gDroneAutoMarkerEqual = NULL;
  480.     }
  481.     
  482.     if (gDroneAutoMarkerAbove != NULL)
  483.     {
  484.         Q3Object_Dispose(gDroneAutoMarkerAbove);
  485.         gDroneAutoMarkerAbove = NULL;
  486.     }
  487.     
  488.     if (gDroneAutoMarkerBelow != NULL)
  489.     {
  490.         Q3Object_Dispose(gDroneAutoMarkerBelow);
  491.         gDroneAutoMarkerBelow = NULL;
  492.     }
  493. }
  494.  
  495.  
  496. /* =============================================================================
  497.  *        Drone_New (internal)
  498.  *
  499.  *    Creates a new drone.
  500.  * ========================================================================== */
  501. TDroneObject Drone_New(
  502.     TDroneOrder            inOrder)
  503. {
  504.     TDroneObject        drone;
  505.     TDroneObject        prev;
  506.     TDroneObject        next;
  507.     
  508.     // Allocate the memory
  509.     drone = (TDroneObject) malloc(sizeof(TDroneData));
  510.     assert(drone != NULL);
  511.     
  512.     drone->thumbprint = kThumbprint_Dead;  // until finished with it
  513.     
  514.     // Find where to insert it
  515.     prev = NULL;
  516.     next = gDroneList;
  517.     while (next != NULL && next->order < inOrder)
  518.     {
  519.         prev = next;
  520.         next = next->next;
  521.     }
  522.     
  523.     // Link it into the list
  524.     drone->prev = prev;
  525.     drone->next = next;
  526.     
  527.     if (prev != NULL)
  528.     {
  529.         prev->next = drone;
  530.     }
  531.     else
  532.     {
  533.         gDroneList = drone;
  534.     }
  535.     
  536.     if (next != NULL)
  537.     {
  538.         next->prev = drone;
  539.     }
  540.     
  541.     // Fill in the defaults
  542.     drone->moveMethod            = NULL;
  543.     drone->updateSoundMethod    = NULL;
  544.     drone->submitMethod            = NULL;
  545.     drone->pickSubmitMethod        = NULL;
  546.     drone->hitMethod            = NULL;
  547.     
  548.     drone->order                = inOrder;
  549.     
  550.     drone->mark                    = false;
  551.     
  552.     drone->position.x            = 0.0;
  553.     drone->position.y            = 0.0;
  554.     drone->position.z            = 0.0;
  555.     
  556.     drone->position1.x            = 0.0;
  557.     drone->position1.y            = 0.0;
  558.     drone->position1.z            = 0.0;
  559.     
  560.     drone->velocity.x            = 0.0;
  561.     drone->velocity.y            = 0.0;
  562.     drone->velocity.z            = 0.0;
  563.     
  564.     drone->velocity1.x            = 0.0;
  565.     drone->velocity1.y            = 0.0;
  566.     drone->velocity1.z            = 0.0;
  567.     
  568.     drone->acceleration.x        = 0.0;
  569.     drone->acceleration.y        = 0.0;
  570.     drone->acceleration.z        = 0.0;
  571.     
  572.     drone->direction.x            = 1.0;
  573.     drone->direction.y            = 0.0;
  574.     drone->direction.z            = 0.0;
  575.     
  576.     drone->up.x                    = 0.0;
  577.     drone->up.y                    = 1.0;
  578.     drone->up.z                    = 0.0;
  579.     
  580.     drone->cross.x                = 0.0;
  581.     drone->cross.y                = 0.0;
  582.     drone->cross.z                = 1.0;
  583.     
  584.     drone->geometry                = NULL;
  585.     
  586.     drone->autoSndChannel        = NULL;
  587.     drone->autoSource            = NULL;
  588.     drone->autoSound            = kAutoSound_None;
  589.     
  590.     drone->autoInterest            = NULL;
  591.     
  592.     drone->autoVelocity.x        = 0.0;
  593.     drone->autoVelocity.y        = 0.0;
  594.     drone->autoVelocity.z        = 0.0;
  595.     
  596.     drone->autoMode                = kAutoMode_Idle;
  597.     drone->autoModeTimeout        = 0;
  598.     drone->autoDistance            = 0.0;
  599.     drone->autoExplosion        = 0.0;
  600.     
  601.     drone->bulletOrigin.x        = 0.0;
  602.     drone->bulletOrigin.y        = 0.0;
  603.     drone->bulletOrigin.z        = 0.0;
  604.     
  605.     return drone;
  606. }
  607.  
  608.  
  609. /* =============================================================================
  610.  *        SelfDrone_New (external)
  611.  *
  612.  *    Creates a new drone whose movement pattern is defined by user controls.
  613.  * ========================================================================== */
  614. TDroneObject SelfDrone_New(
  615.     void)
  616. {
  617.     TDroneObject        drone;
  618.     
  619.     // Create the basic drone
  620.     drone = Drone_New(kDroneOrder_Self);
  621.     assert(drone != NULL);
  622.     
  623.     // Fill in the fields
  624.     drone->moveMethod        = SelfDrone_Move;
  625.     
  626.     // Validate it
  627.     drone->thumbprint        = kThumbprint_SelfDrone;
  628.     
  629.     return drone;
  630. }
  631.  
  632.  
  633. /* =============================================================================
  634.  *        AutoDrone_New (external)
  635.  *
  636.  *    Creates a new drone whose movement pattern is under automatic control.
  637.  * ========================================================================== */
  638. TDroneObject AutoDrone_New(
  639.     TDroneObject            inDroneOfInterest)
  640. {
  641.     TDroneObject            drone;
  642.     TQ3Vector3D                orientation;
  643.     SoundComponentLink        link;
  644.     
  645.     assert(inDroneOfInterest != NULL && IS_DRONE(inDroneOfInterest));
  646.     
  647.     // Create the basic drone
  648.     drone = Drone_New(kDroneOrder_Auto);
  649.     assert(drone != NULL);
  650.     
  651.     // Fill in the fields
  652.     drone->moveMethod        = AutoDrone_Move;
  653.     drone->updateSoundMethod = AutoDrone_UpdateSound;
  654.     drone->submitMethod        = AutoDrone_Submit;
  655.     drone->pickSubmitMethod    = AutoDrone_PickSubmit;
  656.     drone->hitMethod        = AutoDrone_Hit;
  657.     
  658.     // Allocate the sound channel and set up for 3D localized sound
  659.     drone->autoSndChannel    = NULL;
  660.     SndNewChannel(&drone->autoSndChannel, sampledSynth, initMono, NULL);
  661.     assert(drone->autoSndChannel != NULL);
  662.     
  663.     NewSource(&drone->autoSource);
  664.     assert(drone->autoSource != NULL);
  665.     
  666.     link.description.componentType            = kSoundEffectsType;
  667.     link.description.componentSubType        = kSnd3DSubType;
  668.     link.description.componentManufacturer    = 'appl';
  669.     link.description.componentFlags            = 0;        
  670.     link.description.componentFlagsMask        = 0;    
  671.     link.mixerID                            = nil;
  672.     link.linkID                                = nil;
  673.     
  674.     SndSetInfo(drone->autoSndChannel, siPreMixerSoundComponent, &link);
  675.     
  676.     // The sound is loudest out the back of the model
  677.     Q3Vector3D_Set(&orientation, -1.0, 0.0, 0.0);
  678.     SetSourceOrientation(drone->autoSource, &orientation);
  679.     
  680.     drone->autoInterest        = inDroneOfInterest;
  681.     drone->geometry            = Q3Shared_GetReference(gDroneAutoGeometry);
  682.     
  683.     drone->position.x        += Random()*0.0001 + AUTO_DRONE_LEAD;
  684.     drone->position.y        += Random()*0.0001;
  685.     drone->position.z        += Random()*0.0001;
  686.     
  687.     drone->autoVelocity.x    += Random()*0.0001;
  688.     drone->autoVelocity.y    += Random()*0.0001;
  689.     drone->autoVelocity.z    += Random()*0.0001;
  690.     
  691.     // Validate it
  692.     drone->thumbprint        = kThumbprint_AutoDrone;
  693.     
  694.     return drone;
  695. }
  696.  
  697.  
  698. /* =============================================================================
  699.  *        BulletDrone_New (external)
  700.  *
  701.  *    Creates a new drone whose behavior is projectile.
  702.  * ========================================================================== */
  703. TDroneObject BulletDrone_New(
  704.     const TQ3Point3D*        inPosition,
  705.     const TQ3Vector3D*        inDirection)
  706. {
  707.     TDroneObject            drone;
  708.     
  709.     assert(inPosition != NULL);
  710.     assert(inDirection != NULL);
  711.     
  712.     // Create the basic drone
  713.     drone = Drone_New(kDroneOrder_Bullet);
  714.     assert(drone != NULL);
  715.     
  716.     // Fill in the fields
  717.     drone->moveMethod        = BulletDrone_Move;
  718.     drone->submitMethod        = BulletDrone_Submit;
  719.     
  720.     drone->position            = *inPosition;
  721.     drone->direction        = *inDirection;
  722.     
  723.     drone->bulletOrigin        = *inPosition;
  724.     
  725.     // Validate it
  726.     drone->thumbprint        = kThumbprint_BulletDrone;
  727.     
  728.     return drone;
  729. }
  730.  
  731.  
  732. /* =============================================================================
  733.  *        Drone_Dispose (external)
  734.  *
  735.  *    Disposes of the drone.
  736.  * ========================================================================== */
  737. void Drone_Dispose(
  738.     TDroneObject            inDrone)
  739. {
  740.     assert(inDrone != NULL && IS_DRONE(inDrone));
  741.     
  742.     // Unlink it from the list
  743.     if (inDrone->prev != NULL)
  744.     {
  745.         inDrone->prev->next = inDrone->next;
  746.     }
  747.     else
  748.     {
  749.         gDroneList = inDrone->next;
  750.     }
  751.     
  752.     if (inDrone->next != NULL)
  753.     {
  754.         inDrone->next->prev = inDrone->prev;
  755.     }
  756.     
  757.     // Dispose stuff
  758.     if (inDrone->geometry != NULL)
  759.     {
  760.         Q3Object_Dispose(inDrone->geometry);
  761.         inDrone->geometry = NULL;
  762.     }
  763.     
  764.     // Free the sound channel
  765.     //• This rightly belongs in AutoDrone_Dispose
  766.     if (inDrone->autoSource != NULL)
  767.     {
  768.         DisposeSource(inDrone->autoSource);
  769.         inDrone->autoSource = NULL;
  770.     }
  771.     
  772.     if (inDrone->autoSndChannel != NULL)
  773.     {
  774.         SndDisposeChannel(inDrone->autoSndChannel, true);
  775.         inDrone->autoSndChannel = NULL;
  776.     }
  777.     
  778.     // Dispose of the memory
  779.     inDrone->thumbprint = kThumbprint_Dead;
  780.     free(inDrone);
  781. }
  782.  
  783.  
  784. /* =============================================================================
  785.  *        Drone_Next (external)
  786.  *
  787.  *    If inDrone is NULL, then the head of the drone list is returned.  If inDrone
  788.  *    is non-NULL, then the next drone in the list is returned.  If inDrone is the
  789.  *    last drone, then NULL is returned.
  790.  * ========================================================================== */
  791. TDroneObject Drone_Next(
  792.     TDroneObject            inDrone)
  793. {
  794.     TDroneObject            result;
  795.     
  796.     if (inDrone != NULL)
  797.     {
  798.         assert(IS_DRONE(inDrone));
  799.         
  800.         result = inDrone->next;
  801.     }
  802.     else
  803.     {
  804.         result = gDroneList;
  805.     }
  806.     
  807.     return result;
  808. }
  809.  
  810.  
  811. /* =============================================================================
  812.  *        Drone_Move (external)
  813.  *
  814.  *    Moves the drone forward one time step.  This may mark the drone for death.
  815.  * ========================================================================== */
  816. void Drone_Move(
  817.     TDroneObject            inDrone)
  818. {
  819.     assert(inDrone != NULL && IS_DRONE(inDrone));
  820.     
  821.     // Move the drone by its own rules
  822.     assert(inDrone->moveMethod != NULL);
  823.     (inDrone->moveMethod)(inDrone);
  824.     
  825.     // Drone is still alive -- compute the velocity and acceleration
  826.     Q3Point3D_Subtract(&inDrone->position, &inDrone->position1, &inDrone->velocity);
  827.     Q3Vector3D_Scale(&inDrone->velocity, gGameFramesPerSecond, &inDrone->velocity);
  828.     inDrone->position1 = inDrone->position;
  829.     
  830.     Q3Vector3D_Subtract(&inDrone->velocity, &inDrone->velocity1, &inDrone->acceleration);
  831.     Q3Vector3D_Scale(&inDrone->acceleration, gGameFramesPerSecond, &inDrone->acceleration);
  832.     inDrone->velocity1 = inDrone->velocity;
  833.     
  834.     // Reorthogonalize the up and cross vectors
  835.     assert(fabs(Q3Vector3D_Length(&inDrone->direction) - 1.0) < 0.05);
  836.     
  837.     Q3Vector3D_Cross(&inDrone->direction, &inDrone->up, &inDrone->cross);
  838.     Q3Vector3D_Normalize(&inDrone->cross, &inDrone->cross);
  839.     
  840.     Q3Vector3D_Cross(&inDrone->cross, &inDrone->direction, &inDrone->up);
  841. }
  842.  
  843.  
  844. /* =============================================================================
  845.  *        SelfDrone_Move (internal)
  846.  *
  847.  *    Moves the drone forward one time step.
  848.  * ========================================================================== */
  849. void SelfDrone_Move(
  850.     TDroneObject            inDrone)
  851. {
  852.     TQ3Vector3D                v;
  853.     
  854.     assert(inDrone != NULL && IS_SELF_DRONE(inDrone));
  855.     
  856.     Q3Vector3D_Scale(&inDrone->direction, gGameInterval*SELF_DRONE_SPEED, &v);
  857.     Q3Point3D_Vector3D_Add(&inDrone->position, &v, &inDrone->position);
  858. }
  859.  
  860.  
  861. /* =============================================================================
  862.  *        AutoDrone_Move (internal)
  863.  *
  864.  *    Moves the drone forward one time step.  The autopilot drone has a constant
  865.  *    thrust along its direction of orientation.  The direction is controlled to
  866.  *    point just in front of the drone of interest.
  867.  * ========================================================================== */
  868. void AutoDrone_Move(
  869.     TDroneObject            inDrone)
  870. {
  871.     TQ3Vector3D                newDirection;
  872.     TQ3Vector3D                v1;
  873.     TQ3Vector3D                v2;
  874.     TQ3Point3D                target;
  875.     float                    distance;
  876.     float                    turnRate;
  877.     float                    limit;
  878.     TAutoSound                newSound;
  879.     SndCommand                sndCommand;
  880.     long                    base;
  881.     TQ3Matrix4x4            matrix;
  882.     
  883.     assert(inDrone != NULL && IS_AUTO_DRONE(inDrone));
  884.     
  885.     // Figure out new direction
  886.     if (inDrone->autoMode == kAutoMode_Explosion)
  887.     {
  888.         // Point the explosion geometry at the camera
  889.         //• NOTE: For now, we assume that the camera is at the drone of interest
  890.         //• This is wrong for two reasons.  First, the camera could actually be
  891.         //• elsewhere.  Second, this assumes that the drone of interest moves
  892.         //• before this drone.
  893.         Q3Point3D_Subtract(
  894.                 &inDrone->autoInterest->position,
  895.                 &inDrone->position,
  896.                 &newDirection);
  897.         
  898.         Q3Vector3D_Normalize(&newDirection, &inDrone->direction);
  899.     }
  900.     else
  901.     {
  902.         // Find a point in front of the drone of interest
  903.         assert(IS_DRONE(inDrone->autoInterest));
  904.         
  905.         Q3Vector3D_Scale(&inDrone->autoInterest->direction, AUTO_DRONE_LEAD, &v1);
  906.         Q3Point3D_Vector3D_Add(&inDrone->autoInterest->position, &v1, &target);
  907.         
  908.         // Point toward the target
  909.         Q3Point3D_Subtract(&target, &inDrone->position, &newDirection);
  910.         Q3Vector3D_Normalize(&newDirection, &newDirection);
  911.         
  912.         // Limit the turn rate
  913.         turnRate = acosf(Q3Vector3D_Dot(&inDrone->direction, &newDirection));
  914.         limit = AUTO_DRONE_TURN_RATE*gGameInterval;
  915.         if (turnRate > limit)
  916.         {
  917.             // Limit the turn
  918.             // Note: this should actually be spherical interpolation -- but linear is close enough
  919.             turnRate = limit/turnRate;
  920.             Q3Vector3D_Scale(&inDrone->direction, 1.0-turnRate, &v1);
  921.             Q3Vector3D_Scale(&newDirection, turnRate, &v2);
  922.             Q3Vector3D_Add(&v1, &v2, &inDrone->direction);
  923.             Q3Vector3D_Normalize(&inDrone->direction, &inDrone->direction);
  924.         }
  925.         else
  926.         {
  927.             // It's OK to make the desired turn
  928.             inDrone->direction = newDirection;
  929.         }
  930.     }
  931.     
  932.     // Figure out new position
  933.     switch (inDrone->autoMode)
  934.     {
  935.         case kAutoMode_Idle: // Start a burn if we are getting farther from the target
  936.             // Start burn if we are getting farther from the target
  937.             distance = Q3Point3D_Distance(&inDrone->position, &target);
  938.             if (inDrone->autoDistance > distance)
  939.             {
  940.                 // Getting closer to target -- don't change
  941.                 inDrone->autoDistance = distance;
  942.             }
  943.             else
  944.             {
  945.                 // Getting farther from target -- start a burn
  946.                 inDrone->autoMode = kAutoMode_Burn;
  947.                 inDrone->autoModeTimeout = TickCount() + (unsigned long) (AUTO_DRONE_BURN_TIME*60);
  948.             }
  949.         break;
  950.         
  951.         case kAutoMode_Burn: // Accelerate toward the target
  952.             // Continue the burn?
  953.             if (TickCount() <= inDrone->autoModeTimeout)
  954.             {
  955.                 // Still burning -- change the velocity by accelerating toward the target
  956.                 Q3Vector3D_Scale(&inDrone->direction, gGameInterval*AUTO_DRONE_ACCEL, &v1);
  957.                 Q3Vector3D_Add(&inDrone->autoVelocity, &v1, &inDrone->autoVelocity);
  958.             }
  959.             else
  960.             {
  961.                 // Switch to rest mode
  962.                 inDrone->autoMode = kAutoMode_Rest;
  963.                 inDrone->autoModeTimeout = TickCount() + (unsigned long) (AUTO_DRONE_REST_TIME*60);
  964.             }
  965.         break;
  966.         
  967.         case kAutoMode_Rest: // Don't use the engine for a while
  968.             // Continue the rest?
  969.             if (TickCount() <= inDrone->autoModeTimeout)
  970.             {
  971.                 // Still resting
  972.                 // (do nothing)
  973.             }
  974.             else
  975.             {
  976.                 // Switch to idle mode
  977.                 inDrone->autoMode = kAutoMode_Idle;
  978.                 inDrone->autoDistance = Q3Point3D_Distance(&inDrone->position, &target);
  979.             }
  980.         break;
  981.         
  982.         case kAutoMode_Explosion: // Show the explosion for a while
  983.             // Continue the explosion?
  984.             inDrone->autoExplosion += gGameInterval/AUTO_DRONE_EXPLOSION_TIME;
  985.             if (inDrone->autoExplosion <= 1.0)
  986.             {
  987.                 // Still exploding
  988.                 inDrone->autoVelocity.x =
  989.                 inDrone->autoVelocity.y =
  990.                 inDrone->autoVelocity.z = 0.0;
  991.             }
  992.             else
  993.             {
  994.                 // Kill the drone
  995.                 Drone_SetMark(inDrone, true);
  996.             }
  997.         break;
  998.         
  999.         default:
  1000.             assert(0);
  1001.     }
  1002.     
  1003.     // Move along the new velocity vector
  1004.     Q3Vector3D_Scale(&inDrone->autoVelocity, gGameInterval, &v1);
  1005.     Q3Point3D_Vector3D_Add(&inDrone->position, &v1, &inDrone->position);
  1006.     
  1007.     // Choose the next sound to play
  1008.     switch (inDrone->autoMode)
  1009.     {
  1010.         case kAutoMode_Idle:
  1011.         case kAutoMode_Rest:
  1012.             newSound = kAutoSound_Idle;
  1013.         break;
  1014.         
  1015.         case kAutoMode_Burn:
  1016.             newSound = kAutoSound_Burn;
  1017.         break;
  1018.         
  1019.         break;
  1020.         
  1021.         case kAutoMode_Explosion:
  1022.             newSound = kAutoSound_Explosion;
  1023.         break;
  1024.         
  1025.         default:
  1026.             assert(0);
  1027.     }
  1028.     
  1029.     // Change the sound
  1030.     if (inDrone->autoSound != newSound)
  1031.     {
  1032.         // Stop the old sound
  1033.         if (inDrone->autoSound != kAutoSound_None)
  1034.         {
  1035.             sndCommand.cmd = quietCmd;
  1036.             sndCommand.param1 = 0;
  1037.             sndCommand.param2 = 0;
  1038.             SndDoImmediate(inDrone->autoSndChannel, &sndCommand);
  1039.         }
  1040.         
  1041.         inDrone->autoSound = newSound;
  1042.         
  1043.         // Play the new sound
  1044.         switch (inDrone->autoSound)
  1045.         {
  1046.             case kAutoSound_None:
  1047.                 base = 0;
  1048.             break;
  1049.             
  1050.             case kAutoSound_Idle:
  1051.                 base = (long) *gDroneAutoSndIdle + gDroneAutoSndIdleOffset;
  1052.                 SetSourceAngularAttenuation(inDrone->autoSource, 0.0, 0.0);
  1053.                 SetSourceReferenceDistance(inDrone->autoSource, AUTO_DRONE_IDLE_REF_DIST);
  1054.             break;
  1055.             
  1056.             case kAutoSound_Burn:
  1057.                 base = (long) *gDroneAutoSndBurn + gDroneAutoSndBurnOffset;
  1058.                 SetSourceAngularAttenuation(inDrone->autoSource, 1.5, -12.0);
  1059.                 SetSourceReferenceDistance(inDrone->autoSource, AUTO_DRONE_BURN_REF_DIST);
  1060.             break;
  1061.             
  1062.             case kAutoSound_Explosion:
  1063.                 base = (long) *gDroneAutoSndExplosion + gDroneAutoSndExplosionOffset;
  1064.                 SetSourceAngularAttenuation(inDrone->autoSource, 0.0, 0.0);
  1065.                 SetSourceReferenceDistance(inDrone->autoSource, AUTO_DRONE_EXPL_REF_DIST);
  1066.             break;
  1067.             
  1068.             default:
  1069.                 assert(0);
  1070.         }
  1071.         
  1072.         if (base != 0)
  1073.         {
  1074.             // Install the sound
  1075.             sndCommand.cmd = soundCmd;
  1076.             sndCommand.param1 = 0;
  1077.             sndCommand.param2 = base;
  1078.             SndDoImmediate(inDrone->autoSndChannel, &sndCommand);
  1079.             
  1080.             // Play it indefinitely
  1081.             sndCommand.cmd = freqCmd;
  1082.             sndCommand.param1 = 0;
  1083.             sndCommand.param2 = 60;
  1084.             SndDoImmediate(inDrone->autoSndChannel, &sndCommand);
  1085.         }
  1086.     }
  1087.     
  1088.     // Change the sound source location
  1089.     Drone_GetMatrix(inDrone, &matrix);
  1090.     SetSourceTransform(inDrone->autoSource, &matrix);
  1091. }
  1092.  
  1093.  
  1094. /* =============================================================================
  1095.  *        BulletDrone_Move (internal)
  1096.  *
  1097.  *    Moves the drone forward one time step.
  1098.  * ========================================================================== */
  1099. void BulletDrone_Move(
  1100.     TDroneObject            inDrone)
  1101. {
  1102.     TQ3Vector3D                v;
  1103.     float                    prevDistance;
  1104.     float                    currDistance;
  1105.     TQ3CameraPlacement        placement;
  1106.     TDroneObject            target;
  1107.     unsigned long            count;
  1108.     unsigned long            index;
  1109.     TQ3HitData                hitData;
  1110.     
  1111.     assert(inDrone != NULL && IS_BULLET_DRONE(inDrone));
  1112.     
  1113.     // Move the bullet
  1114.     prevDistance = Q3Point3D_Distance(&inDrone->position, &inDrone->bulletOrigin);
  1115.     
  1116.     Q3Vector3D_Scale(&inDrone->direction, gGameInterval*BULLET_DRONE_SPEED, &v);
  1117.     Q3Point3D_Vector3D_Add(&inDrone->position, &v, &inDrone->position);
  1118.     
  1119.     currDistance = Q3Point3D_Distance(&inDrone->position, &inDrone->bulletOrigin);
  1120.     
  1121.     // Time to expire?
  1122.     if (currDistance > BULLET_DRONE_LIMIT)
  1123.     {
  1124.         // Mark the drone to die
  1125.         Drone_SetMark(inDrone, true);
  1126.     }
  1127.     else
  1128.     {
  1129.         // Set up for collision detection
  1130.         placement.cameraLocation    = inDrone->bulletOrigin;
  1131.         placement.upVector            = inDrone->up;
  1132.         
  1133.         Q3Point3D_Vector3D_Add(&inDrone->bulletOrigin, &inDrone->direction, &placement.pointOfInterest);
  1134.         
  1135.         Q3Camera_SetPlacement(gDroneCamera, &placement);
  1136.         
  1137.         // Collision detection with all target drones
  1138.         Q3View_StartPicking(gDroneView, gDronePick);
  1139.         do
  1140.         {
  1141.             for (target = Drone_Next(NULL); target != NULL; target = Drone_Next(target))
  1142.             {
  1143.                 // Submit the drone geometry, along with a PickID that is the object reference
  1144.                 Q3PickIDStyle_Submit((unsigned long) target, gDroneView);
  1145.                 Drone_PickSubmit(target, gDroneView);
  1146.             }
  1147.         }
  1148.         while (Q3View_EndPicking(gDroneView) == kQ3ViewStatusRetraverse);
  1149.         
  1150.         // Check the hit list
  1151.         Q3Pick_GetNumHits(gDronePick, &count);
  1152.         for (index = 0; index < count; index++)
  1153.         {
  1154.             Q3Pick_GetHitData(gDronePick, index, &hitData);
  1155.             
  1156.             if ((hitData.validMask & kQ3PickDetailMaskPickID) &&
  1157.                 (hitData.validMask & kQ3PickDetailMaskDistance))
  1158.             {
  1159.                 target = (TDroneObject) hitData.pickID;
  1160.                 
  1161.                 if (target != NULL && IS_DRONE(target))
  1162.                 {
  1163.                     // Got a valid hit -- check its range
  1164.                     //• Should it be a bullet or a laser?
  1165.                     if ((1 || prevDistance <= hitData.distance) && hitData.distance <= currDistance)
  1166.                     {
  1167.                         // Hit it!
  1168.                         Drone_Hit(target);
  1169.                         
  1170.                         // Kill the bullet
  1171.                         Drone_SetMark(inDrone, true);
  1172.                         break;
  1173.                     }
  1174.                 }
  1175.             }
  1176.             
  1177.             Q3Hit_EmptyData(&hitData);
  1178.         }
  1179.         
  1180.         // Empty out the pick hits
  1181.         Q3Pick_EmptyHitList(gDronePick);
  1182.     }
  1183. }
  1184.  
  1185.  
  1186. /* =============================================================================
  1187.  *        Drone_UpdateSound (external)
  1188.  *
  1189.  *    Updates localized sounds for this drone.  The default method does nothing.
  1190.  * ========================================================================== */
  1191. void Drone_UpdateSound(
  1192.     TDroneObject            inDrone)
  1193. {
  1194.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1195.     
  1196.     if (inDrone->updateSoundMethod != NULL)
  1197.     {
  1198.         (inDrone->updateSoundMethod)(inDrone);
  1199.     }
  1200. }
  1201.  
  1202.  
  1203. /* =============================================================================
  1204.  *        AutoDrone_UpdateSound (external)
  1205.  *
  1206.  *    Updates localized sounds for this autopilot drone.
  1207.  * ========================================================================== */
  1208. void AutoDrone_UpdateSound(
  1209.     TDroneObject            inDrone)
  1210. {
  1211.     Snd3DInfo                snd3DInfo;
  1212.     
  1213.     assert(inDrone != NULL && IS_AUTO_DRONE(inDrone));
  1214.     
  1215.     GetSource3DInfo(inDrone->autoSource, Sound_GetListener(), &snd3DInfo);
  1216.     
  1217.     SndSetInfo(inDrone->autoSndChannel, si3DInfo, &snd3DInfo);
  1218. }
  1219.  
  1220.  
  1221. /* =============================================================================
  1222.  *        Drone_Submit (external)
  1223.  *
  1224.  *    Submits the drone for drawing.
  1225.  * ========================================================================== */
  1226. void Drone_Submit(
  1227.     TDroneObject            inDrone,
  1228.     Boolean                    inHUDVisible,
  1229.     TQ3ViewObject            inView)
  1230. {
  1231.     TQ3Matrix4x4            matrix;
  1232.     
  1233.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1234.     
  1235.     if (inDrone->submitMethod != NULL)
  1236.     {
  1237.         // Use the submit method
  1238.         (inDrone->submitMethod)(inDrone, inHUDVisible, inView);
  1239.     }
  1240.     else if (inDrone->geometry != NULL)
  1241.     {
  1242.         // Submit the geometry
  1243.         Drone_GetMatrix(inDrone, &matrix);
  1244.         
  1245.         Q3Push_Submit(inView);
  1246.         Q3MatrixTransform_Submit(&matrix, inView);
  1247.         Q3Object_Submit(inDrone->geometry, inView);
  1248.         Q3Pop_Submit(inView);
  1249.     }
  1250. }
  1251.  
  1252.  
  1253. /* =============================================================================
  1254.  *        AutoDrone_Submit (internal)
  1255.  *
  1256.  *    Submits the bullet drone for drawing.
  1257.  * ========================================================================== */
  1258. void AutoDrone_Submit(
  1259.     TDroneObject            inDrone,
  1260.     Boolean                    inHUDVisible,
  1261.     TQ3ViewObject            inView)
  1262. {
  1263.     TQ3Matrix4x4            matrix;
  1264.     TQ3ColorRGB                transparency;
  1265.     TQ3Point3D                position;
  1266.     TQ3Vector3D                direction;
  1267.     TQ3Vector3D                up;
  1268.     TQ3Vector3D                right;
  1269.     TQ3Vector3D                v;
  1270.     TQ3Vector3D                v1;
  1271.     TQ3Vector3D                v2;
  1272.     float                    height;
  1273.     TQ3GeometryObject        marker;
  1274.     
  1275.     assert(inDrone != NULL && IS_AUTO_DRONE(inDrone));
  1276.     assert(inView != NULL);
  1277.     
  1278.     // Draw the drone
  1279.     Q3Push_Submit(inView);
  1280.     
  1281.     Drone_GetMatrix(inDrone, &matrix);
  1282.     Q3MatrixTransform_Submit(&matrix, inView);
  1283.     
  1284.     switch (inDrone->autoMode)
  1285.     {
  1286.         case kAutoMode_Burn:
  1287.             Q3Object_Submit(gDroneAutoBurnGeometry, inView);
  1288.             /* FALL THROUGH TO SUBMIT DRONE GEOMETRY */
  1289.         
  1290.         case kAutoMode_Rest:
  1291.         case kAutoMode_Idle:
  1292.             Q3Object_Submit(inDrone->geometry, inView);
  1293.         break;
  1294.         
  1295.         case kAutoMode_Explosion:
  1296.             // Grow the explosion
  1297.             v.x = v.y = v.z = (1.0-AUTO_DRONE_MIN_SCALE)*inDrone->autoExplosion + AUTO_DRONE_MIN_SCALE;
  1298.             Q3ScaleTransform_Submit(&v, inView);
  1299.             
  1300.             // Fade at the end
  1301.             if (inDrone->autoExplosion > (1.0-AUTO_DRONE_FADE_TIME))
  1302.             {
  1303.                 transparency.r =
  1304.                 transparency.g =
  1305.                 transparency.b = (-1.0/AUTO_DRONE_FADE_TIME)*inDrone->autoExplosion + (1.0/AUTO_DRONE_FADE_TIME);
  1306.                 
  1307.                 Q3Attribute_Submit(kQ3AttributeTypeTransparencyColor, &transparency, inView);
  1308.             }
  1309.             
  1310.             // Submit the explosion geometry
  1311.             Q3Object_Submit(gDroneAutoExplosionGeometry, inView);
  1312.         break;
  1313.         
  1314.         default:
  1315.             assert(0);
  1316.     }
  1317.     
  1318.     Q3Pop_Submit(inView);
  1319.     
  1320.     // Draw the HUD marker for the drone
  1321.     if (inHUDVisible && inDrone->autoMode != kAutoMode_Explosion)
  1322.     {
  1323.         Display_GetViewerPosition(&position, &direction, &up);
  1324.         Q3Vector3D_Cross(&direction, &up, &right);
  1325.         
  1326.         Q3Point3D_Subtract(&inDrone->position, &position, &v);
  1327.         
  1328.         Q3Vector3D_Scale(&up,    HUD_SCALE*Q3Vector3D_Dot(&direction, &v), &v1);
  1329.         Q3Vector3D_Scale(&right, HUD_SCALE*Q3Vector3D_Dot(&right,     &v), &v2);
  1330.         
  1331.         Q3Point3D_Vector3D_Add(&position, &direction, &position);
  1332.         Q3Point3D_Vector3D_Add(&position, &v1,        &position);
  1333.         Q3Point3D_Vector3D_Add(&position, &v2,        &position);
  1334.         
  1335.         Q3Vector3D_Normalize(&v, &v);
  1336.         height = Q3Vector3D_Dot(&up, &v);
  1337.         if (height >= HUD_HEIGHT)
  1338.         {
  1339.             marker = gDroneAutoMarkerAbove;
  1340.         }
  1341.         else if (height <= -HUD_HEIGHT)
  1342.         {
  1343.             marker = gDroneAutoMarkerBelow;
  1344.         }
  1345.         else
  1346.         {
  1347.             marker = gDroneAutoMarkerEqual;
  1348.         }
  1349.         
  1350.         Q3Marker_SetPosition(marker, &position);
  1351.         Q3Object_Submit(marker, inView);
  1352.     }
  1353. }
  1354.  
  1355.  
  1356. /* =============================================================================
  1357.  *        BulletDrone_Submit (internal)
  1358.  *
  1359.  *    Submits the bullet drone for drawing.
  1360.  * ========================================================================== */
  1361. void BulletDrone_Submit(
  1362.     TDroneObject            inDrone,
  1363.     Boolean                    inHUDVisible,
  1364.     TQ3ViewObject            inView)
  1365. {
  1366.     TQ3LineData                lineData;
  1367.     
  1368.     assert(inDrone != NULL && IS_BULLET_DRONE(inDrone));
  1369.     assert(inView != NULL);
  1370.     
  1371.     lineData.vertices[0].point            = inDrone->bulletOrigin;
  1372.     lineData.vertices[0].attributeSet    = NULL;
  1373.     lineData.vertices[1].point            = inDrone->position;
  1374.     lineData.vertices[1].attributeSet    = NULL;
  1375.     lineData.lineAttributeSet            = NULL;
  1376.     
  1377.     Q3Push_Submit(inView);
  1378.     Q3Object_Submit(gDroneNULLIllumination, inView);
  1379.     Q3Object_Submit(gDroneBulletColor, inView);
  1380.     Q3Line_Submit(&lineData, inView);
  1381.     Q3Pop_Submit(inView);
  1382. }
  1383.  
  1384.  
  1385. /* =============================================================================
  1386.  *        Drone_PickSubmit (internal)
  1387.  *
  1388.  *    Submits the drone for picking against a bullet.  It forwards to the actual
  1389.  *    drone hit method, if any.
  1390.  * ========================================================================== */
  1391. void Drone_PickSubmit(
  1392.     TDroneObject            inDrone,
  1393.     TQ3ViewObject            inView)
  1394. {
  1395.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1396.     
  1397.     if (inDrone->pickSubmitMethod != NULL)
  1398.     {
  1399.         (*inDrone->pickSubmitMethod)(inDrone, inView);
  1400.     }
  1401. }
  1402.  
  1403.  
  1404. /* =============================================================================
  1405.  *        AutoDrone_PickSubmit (internal)
  1406.  *
  1407.  *    Submits the autopilot drone for picking against a bullet.
  1408.  * ========================================================================== */
  1409. void AutoDrone_PickSubmit(
  1410.     TDroneObject            inDrone,
  1411.     TQ3ViewObject            inView)
  1412. {
  1413.     TQ3Matrix4x4            matrix;
  1414.     
  1415.     assert(inDrone != NULL && IS_AUTO_DRONE(inDrone));
  1416.     assert(inView != NULL);
  1417.     
  1418.     // Draw the drone
  1419.     if (inDrone->autoMode != kAutoMode_Explosion)
  1420.     {
  1421.         Q3Push_Submit(inView);
  1422.         
  1423.         Drone_GetMatrix(inDrone, &matrix);
  1424.         Q3MatrixTransform_Submit(&matrix, inView);
  1425.         
  1426.         Q3Object_Submit(gDroneAutoBurnGeometry, inView);
  1427.         
  1428.         Q3Pop_Submit(inView);
  1429.     }
  1430. }
  1431.  
  1432.  
  1433. /* =============================================================================
  1434.  *        Drone_Hit (internal)
  1435.  *
  1436.  *    Called when this drone is hit.  It forwards to the actual drone hit method,
  1437.  *    if any.
  1438.  * ========================================================================== */
  1439. void Drone_Hit(
  1440.     TDroneObject            inDrone)
  1441. {
  1442.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1443.     
  1444.     if (inDrone->hitMethod != NULL)
  1445.     {
  1446.         (*inDrone->hitMethod)(inDrone);
  1447.     }
  1448. }
  1449.  
  1450.  
  1451. /* =============================================================================
  1452.  *        AutoDrone_Hit (internal)
  1453.  *
  1454.  *    Called when this autopilot drone is hit.  It puts the drone into
  1455.  *    explosion mode.
  1456.  * ========================================================================== */
  1457. void AutoDrone_Hit(
  1458.     TDroneObject            inDrone)
  1459. {
  1460.     assert(inDrone != NULL && IS_AUTO_DRONE(inDrone));
  1461.     
  1462.     inDrone->autoMode = kAutoMode_Explosion;
  1463.     inDrone->autoExplosion = 0.0;
  1464. }
  1465.  
  1466.  
  1467. /* =============================================================================
  1468.  *        Drone_SetMark (external)
  1469.  *
  1470.  *    Changes the drone's mark to the given value.  The mark is used to indicate
  1471.  *    which drones should die.
  1472.  * ========================================================================== */
  1473. void Drone_SetMark(
  1474.     TDroneObject            inDrone,
  1475.     Boolean                    inMark)
  1476. {
  1477.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1478.     
  1479.     inDrone->mark = inMark;
  1480. }
  1481.  
  1482.  
  1483. /* =============================================================================
  1484.  *        Drone_GetMark (external)
  1485.  *
  1486.  *    Returns the drone's mark.
  1487.  * ========================================================================== */
  1488. Boolean Drone_GetMark(
  1489.     TDroneObject            inDrone)
  1490. {
  1491.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1492.     
  1493.     return inDrone->mark;
  1494. }
  1495.  
  1496.  
  1497. /* =============================================================================
  1498.  *        Drone_GetPosition (external)
  1499.  *
  1500.  *    Returns the current position in outPosition.
  1501.  * ========================================================================== */
  1502. void Drone_GetPosition(
  1503.     TDroneObject            inDrone,
  1504.     TQ3Point3D*                outPosition)
  1505. {
  1506.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1507.     assert(outPosition != NULL);
  1508.     
  1509.     *outPosition = inDrone->position;
  1510. }
  1511.  
  1512.  
  1513. /* =============================================================================
  1514.  *        Drone_GetDirection (external)
  1515.  *
  1516.  *    Returns the current direction in outDirection.
  1517.  * ========================================================================== */
  1518. void Drone_GetDirection(
  1519.     TDroneObject            inDrone,
  1520.     TQ3Vector3D*            outDirection)
  1521. {
  1522.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1523.     assert(outDirection != NULL);
  1524.     
  1525.     *outDirection = inDrone->direction;
  1526. }
  1527.  
  1528.  
  1529. /* =============================================================================
  1530.  *        Drone_GetUp (external)
  1531.  *
  1532.  *    Returns the current up vector in outUp.
  1533.  * ========================================================================== */
  1534. void Drone_GetUp(
  1535.     TDroneObject            inDrone,
  1536.     TQ3Vector3D*            outUp)
  1537. {
  1538.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1539.     assert(outUp != NULL);
  1540.     
  1541.     *outUp = inDrone->up;
  1542. }
  1543.  
  1544.  
  1545. /* =============================================================================
  1546.  *        Drone_GetMatrix (external)
  1547.  *
  1548.  *    Returns the matrix that transforms to the drone position and orientation.
  1549.  * ========================================================================== */
  1550. void Drone_GetMatrix(
  1551.     TDroneObject            inDrone,
  1552.     TQ3Matrix4x4*            outMatrix)
  1553. {
  1554.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1555.     assert(outMatrix != NULL);
  1556.     
  1557.     outMatrix->value[0][0] = inDrone->direction.x;
  1558.     outMatrix->value[0][1] = inDrone->direction.y;
  1559.     outMatrix->value[0][2] = inDrone->direction.z;
  1560.     
  1561.     outMatrix->value[1][0] = inDrone->up.x;
  1562.     outMatrix->value[1][1] = inDrone->up.y;
  1563.     outMatrix->value[1][2] = inDrone->up.z;
  1564.     
  1565.     outMatrix->value[2][0] = inDrone->cross.x;
  1566.     outMatrix->value[2][1] = inDrone->cross.y;
  1567.     outMatrix->value[2][2] = inDrone->cross.z;
  1568.     
  1569.     outMatrix->value[3][0] = inDrone->position.x;
  1570.     outMatrix->value[3][1] = inDrone->position.y;
  1571.     outMatrix->value[3][2] = inDrone->position.z;
  1572.     
  1573.     outMatrix->value[0][3] = 0.0;
  1574.     outMatrix->value[1][3] = 0.0;
  1575.     outMatrix->value[2][3] = 0.0;
  1576.     outMatrix->value[3][3] = 1.0;
  1577. }
  1578.  
  1579.  
  1580. /* =============================================================================
  1581.  *        Drone_Fire (external)
  1582.  *
  1583.  *    Called each time the fire button is pressed.
  1584.  * ========================================================================== */
  1585. void Drone_Fire(
  1586.     TDroneObject            inDrone)
  1587. {
  1588.     TQ3Vector3D                up;
  1589.     TQ3Vector3D                cross;
  1590.     TQ3Point3D                origin;
  1591.     
  1592.     assert(inDrone != NULL && IS_DRONE(inDrone));
  1593.     
  1594.     // Find the offsets
  1595.     Q3Vector3D_Scale(&inDrone->up,        BULLET_DRONE_OFFSET, &up);
  1596.     Q3Vector3D_Scale(&inDrone->cross,    BULLET_DRONE_OFFSET, &cross);
  1597.     
  1598.     // Fire one
  1599.     Q3Point3D_Vector3D_Subtract(&inDrone->position, &up, &origin);
  1600.     Q3Point3D_Vector3D_Subtract(&origin, &cross, &origin);
  1601.     BulletDrone_New(&origin, &inDrone->direction);
  1602.     
  1603.     // Fire two
  1604.     Q3Point3D_Vector3D_Subtract(&inDrone->position, &up, &origin);
  1605.     Q3Point3D_Vector3D_Add(&origin, &cross, &origin);
  1606.     BulletDrone_New(&origin, &inDrone->direction);
  1607. }
  1608.  
  1609.  
  1610. /* =============================================================================
  1611.  *        SelfDrone_Turn (external)
  1612.  *
  1613.  *    Changes the direction of the ship by the given angles, in radians.
  1614.  * ========================================================================== */
  1615. void SelfDrone_Turn(
  1616.     TDroneObject            inDrone,
  1617.     float                    inHorzAngle,
  1618.     float                    inVertAngle)
  1619. {
  1620.     TQ3Vector3D                v1;
  1621.     TQ3Vector3D                v2;
  1622.     
  1623.     assert(inDrone != NULL && IS_SELF_DRONE(inDrone));
  1624.     
  1625.     if (inHorzAngle != 0.0)
  1626.     {
  1627.         Q3Vector3D_Scale(&inDrone->direction, cosf(inHorzAngle), &v1);
  1628.         Q3Vector3D_Scale(&inDrone->cross,     sinf(inHorzAngle), &v2);
  1629.         Q3Vector3D_Add(&v1, &v2, &inDrone->direction);
  1630.     }
  1631.     
  1632.     if (inVertAngle != 0.0)
  1633.     {
  1634.         Q3Vector3D_Scale(&inDrone->direction, cosf(inVertAngle), &v1);
  1635.         Q3Vector3D_Scale(&inDrone->up,        sinf(inVertAngle), &v2);
  1636.         Q3Vector3D_Add(&v1, &v2, &inDrone->direction);
  1637.     }
  1638. }
  1639.  
  1640.  
  1641.